package mt.client.GUI;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;

import mt.Order;
import mt.client.MicroTraderClient;
import mt.client.OrderResume;
import mt.client.StockResume;
import mt.comm.ClientComm;
import Network.ClientCommunication;

public class ClientGUI extends JFrame implements MicroTraderClient {

	private static final long serialVersionUID = 1L;
	public OrderResume orderResume;
	public ClientCommunication client;
	// private JTextField txtPriceUnit;
	private JTextField txtNumberUnits;
	private JTextField txtStockName;
	public JList<StockResume> listPaneSell;
	private JList<StockResume> listPaneBuy;
	JList<String> listPaneStockDetails;
	public DefaultListModel<StockResume> listModelBuy;
	public DefaultListModel<StockResume> listModelSell;
	public DefaultListModel<String> listModelDetails;
	public ArrayList<StockResume> stockResume;
	public static ArrayList<StockResume> buyOrdersResume;

	public static final int ONE = 1;
	public static final int ZERO = 0;
	/**
	 * Launch the application.
	 */

	ListDataListener listDataListener = new ListDataListener() {
		public void contentsChanged(ListDataEvent listDataEvent) {
			appendEvent(listDataEvent);
		}

		public void intervalAdded(ListDataEvent listDataEvent) {
			appendEvent(listDataEvent);
		}

		public void intervalRemoved(ListDataEvent listDataEvent) {
			appendEvent(listDataEvent);
		}

		private void appendEvent(ListDataEvent listDataEvent) {

		}
	};

	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					ClientGUI frame = new ClientGUI();

					ClientCommunication clientCommDummy = new ClientCommunication(
							"localhost", "es-2014-group59");

					frame.start(clientCommDummy);

					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});

	}

	/**
	 * Receives as parameters the number of units the buyer wants to order and
	 * the StockResume containing the stock details. If the stock ordered
	 * quantity is available it updates its quantity after the stock is ordered.
	 * If the ordered quantity equals the stocks on sale, the stock is removed
	 * from the listPaneSell. If the order exceeds the available stock quantity
	 * a buy order is created in listPaneBuy with the remain quantity and client
	 * nickname
	 * 
	 * @param buyUnits
	 *            - the number of units
	 * @param stockResume
	 *            - stock details
	 */

	public void placeOrder(String buyUnits, StockResume stockResume) {

		try {

			int buyQuantity = Integer.parseInt(buyUnits);

			if (buyQuantity == ZERO || stockResume == null) {
				listModelDetails.removeAllElements();
				listModelDetails
				.addElement("Please introduce the number of orders");
				listModelDetails.addElement(", greater than zero");
				listModelDetails.addElement(", and select a stock");
				return;
			}
			if (stockResume != null) {
				if (stockResume.getTotalUnits() > ZERO && buyQuantity > ZERO
						&& buyQuantity <= stockResume.getTotalUnits()) {
					stockResume.setTotalUnits(stockResume.getTotalUnits()
							- buyQuantity);
					listPaneSell.repaint();
					listPaneSell.clearSelection();
					listModelDetails.removeAllElements();

					if (stockResume.getTotalUnits() == ZERO) {
						listModelSell.removeElement(stockResume);
						listModelDetails.removeAllElements();

					}
				} else if (buyQuantity > stockResume.getTotalUnits()) {


					int quantity = buyQuantity - stockResume.getTotalUnits();
					LinkedList<Order> orders = stockResume.getOrdersList();

					Iterator<Order> iter = orders.iterator();
					while (iter.hasNext()) {
						if (iter.next().isSellOrder()) {
							iter.remove();
						}
					}



					boolean orderResumeExists = false;
					for (StockResume sr : this.stockResume) {
						if (sr.getStock().equals(stockResume.getStock())&& sr.isBuyOrder()) {

							sr.getOrdersList().add(Order.createBuyOrder(client.getNickname(),
									stockResume.getStock(), quantity,
									stockResume.getMedianPrice()));

							sr.setTotalUnits(sr.getTotalUnits()+quantity);							
							listPaneBuy.repaint();
							orderResumeExists = true;
							break;
						}


					} 				
					if (!orderResumeExists) {

						orders.add(Order.createBuyOrder(client.getNickname(),
								stockResume.getStock(), quantity,
								stockResume.getMedianPrice()));

						stockResume.setTotalUnits(quantity);
						stockResume.setBuyOrder(true);
						listModelBuy.addElement(stockResume);

					} 


					listModelSell.removeElement(stockResume);
					listModelDetails.removeAllElements();

				} else {
					listModelDetails.removeAllElements();
					listModelDetails
					.addElement("Please introduce the number of orders");
					listModelDetails.addElement(", greater than zero");
					listModelDetails.addElement(", and select a stock");
					return;
				}
				txtStockName.setText("");
				txtNumberUnits.setText("");

			}
		} catch (NumberFormatException exc) {
			listModelDetails.removeAllElements();
			listModelDetails
			.addElement("Please introduce the number of orders");
			listModelDetails.addElement(", greater than zero");
		}

	}

	/**
	 * Receives as parameter the stock selected by the Buyer and triggers the
	 * display of the stock details
	 * 
	 * @param stockResume
	 *            - stock details
	 */

	public void selectOrder(StockResume stockResume) {

		JList<StockResume> selection = stockResume.isBuyOrder() ? listPaneSell
				: listPaneBuy;

		selection.clearSelection();
		if (stockResume != null) {
			listModelDetails.removeAllElements();
			txtStockName.setText(stockResume.getStock());

			LinkedList<Order> orders = (LinkedList<Order>) stockResume
					.getOrdersList();
			int index = 0;
			for (Order order : orders) {
				if (index > 0) {
					listModelDetails.addElement("---------------");
				}
				listModelDetails.addElement("NickName: " + order.getNickname());
				listModelDetails.addElement("Units: "
						+ order.getNumberOfUnits());
				listModelDetails
				.addElement("Price: " + order.getPricePerUnit());
				index++;
			}

		}

	}

	/**
	 * 
	 * @param orders
	 *            - the orders made bye the clients
	 * @param stockResume
	 *            - contains the stock details
	 * 
	 *            Receives a list of sell and buy Order and a list of
	 *            StockResume. This method filters the sell and Buy Orders
	 *            received and groups all the orders of the same type (buy or
	 *            sell) and same stock and keeps them in list of StockResume
	 */

	public void setStockResume(ArrayList<Order> orders,
			ArrayList<StockResume> stockResume) {

		for (Order order : orders) {
			if (stockResume.isEmpty()) {
				if (order.isBuyOrder()) {
					StockResume.BuyOrdersResume ordersResume = new StockResume.BuyOrdersResume(
							order.getStock());
					ordersResume.addOrder(order);
					ordersResume.setBuyOrder(true);
					stockResume.add(ordersResume);
				}

				else {

					StockResume.SellOrdersResume ordersResume = new StockResume.SellOrdersResume(
							order.getStock());
					ordersResume.addOrder(order);
					stockResume.add(ordersResume);

				}
			} else {
				boolean orderResumeExists = false;
				for (StockResume sr : stockResume) {
					if (sr.getStock().equals(order.getStock())) {
						if (sr instanceof StockResume.SellOrdersResume
								&& !order.isBuyOrder()){
							sr.addOrder(order);
							orderResumeExists = true;
							break;
						}
						else if (sr instanceof StockResume.BuyOrdersResume
								&& order.isBuyOrder()) {
							sr.addOrder(order);
							orderResumeExists = true;
							break;

						}

					} 				}
				if (!orderResumeExists) {
					if (order.isBuyOrder()) {

						StockResume.BuyOrdersResume ordersResume = new StockResume.BuyOrdersResume(
								order.getStock());
						ordersResume.addOrder(order);
						ordersResume.setBuyOrder(true);
						stockResume.add(ordersResume);

					} else {

						StockResume.SellOrdersResume ordersResume = new StockResume.SellOrdersResume(
								order.getStock());
						ordersResume.addOrder(order);
						stockResume.add(ordersResume);
					}
				}
			}
		}

	}

	/**
	 * Create the frame.
	 */
	@SuppressWarnings("static-access")
	public ClientGUI() {
		this.stockResume = new ArrayList<StockResume>();
		this.buyOrdersResume = new ArrayList<StockResume>();

		this.orderResume = new OrderResume();
		this.client = new ClientCommunication();

		listModelBuy = new DefaultListModel<StockResume>();
		listModelSell = new DefaultListModel<StockResume>();
		listModelDetails = new DefaultListModel<String>();

		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 689, 546);

		// MENU BAR

		JMenuBar menuBar = new JMenuBar();
		setJMenuBar(menuBar);
		// CONNECTIVITY
		JMenu mnConnectivity = new JMenu("Connectivity");
		menuBar.add(mnConnectivity);
		// FIND SERVERS
		JMenuItem mntmdFindServers = new JMenuItem("Find Servers");
		mnConnectivity.add(mntmdFindServers);
		// DISCONNECT
		JMenuItem mntmDisconnect = new JMenuItem("Disconnect");
		mnConnectivity.add(mntmDisconnect);
		// PROFILE
		JMenu mnProfile = new JMenu("Profile");
		menuBar.add(mnProfile);
		// ORDER HISTORY
		JMenuItem mntmOrderHistory = new JMenuItem("Order History");
		mnProfile.add(mntmOrderHistory);

		// DISPLAY

		JPanel panelDisplay = new JPanel();
		getContentPane().add(panelDisplay, BorderLayout.CENTER);
		panelDisplay.setLayout(new GridLayout(0, 1, 0, 0));
		// SELL

		JPanel panelSell = new JPanel();
		panelDisplay.add(panelSell);
		panelSell.setLayout(new BorderLayout(0, 0));
		// LABEL
		JLabel lblSell = new JLabel("Sell");
		lblSell.setHorizontalAlignment(JLabel.CENTER);
		panelSell.add(lblSell, BorderLayout.NORTH);
		// LISTA
		listPaneSell = new JList<StockResume>(listModelSell);

		JScrollPane scrollPaneSell = new JScrollPane(listPaneSell);
		panelSell.add(scrollPaneSell, BorderLayout.CENTER);
		// BUY

		JPanel panelBuy = new JPanel();
		panelDisplay.add(panelBuy);
		panelBuy.setLayout(new BorderLayout(0, 0));
		// LABEL
		JLabel lblBuy = new JLabel("Buy");
		lblBuy.setHorizontalAlignment(JLabel.CENTER);
		panelBuy.add(lblBuy, BorderLayout.NORTH);
		// LISTA
		listPaneBuy = new JList<StockResume>(listModelBuy);

		JScrollPane scrollPaneBuy = new JScrollPane(listPaneBuy);
		panelBuy.add(scrollPaneBuy, BorderLayout.CENTER);
		// STOCK DETAILS PANEL
		JPanel panelStockDetails = new JPanel();
		getContentPane().add(panelStockDetails, BorderLayout.EAST);
		panelStockDetails.setLayout(new BorderLayout(0, 0));

		JLabel lblStockDetails = new JLabel("Stock Details");
		panelStockDetails.add(lblStockDetails, BorderLayout.NORTH);

		listPaneStockDetails = new JList<String>(listModelDetails);
		JScrollPane scrollPaneStockDetails = new JScrollPane(
				listPaneStockDetails);
		panelStockDetails.add(scrollPaneStockDetails, BorderLayout.CENTER);

		listPaneBuy.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {

				selectOrder((StockResume) listPaneBuy.getSelectedValue());

			}
		});

		listPaneSell.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {

				selectOrder((StockResume) listPaneSell.getSelectedValue());

			}
		});

		// CONTROLS

		JPanel panelControl = new JPanel();
		getContentPane().add(panelControl, BorderLayout.SOUTH);
		panelControl.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));

		JButton btnPlaceOrder = new JButton("Place Order");

		btnPlaceOrder.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				StockResume stockResume = ((StockResume) listPaneSell
						.getSelectedValue());

				placeOrder(txtNumberUnits.getText().trim(), stockResume);

			}

		});
		panelControl.add(btnPlaceOrder);
		JButton spontaneousOrder = new JButton("Spontaneous Order");
		panelControl.add(spontaneousOrder);

		listModelBuy.addListDataListener(listDataListener);
		JPanel panelPlaceOrder = new JPanel();
		panelStockDetails.add(panelPlaceOrder, BorderLayout.SOUTH);
		panelPlaceOrder
		.setLayout(new FlowLayout(

				new ColumnSpec[] { ColumnSpec.decode("114px"),
						FormFactory.RELATED_GAP_COLSPEC,
						ColumnSpec.decode("default:grow"),
						FormFactory.RELATED_GAP_COLSPEC,
						ColumnSpec.decode("default:grow"), }

				,

				new RowSpec[] { FormFactory.RELATED_GAP_ROWSPEC,
						FormFactory.DEFAULT_ROWSPEC,
						FormFactory.RELATED_GAP_ROWSPEC,
						FormFactory.DEFAULT_ROWSPEC,
						FormFactory.RELATED_GAP_ROWSPEC,
						FormFactory.DEFAULT_ROWSPEC,
						FormFactory.RELATED_GAP_ROWSPEC,
						FormFactory.DEFAULT_ROWSPEC,
						FormFactory.RELATED_GAP_ROWSPEC, }));

		JLabel lblStock = new JLabel("Stock");
		panelPlaceOrder.add(lblStock, "1, 2, left, default");

		txtStockName = new JTextField();
		txtStockName.setEditable(false);
		panelPlaceOrder.add(txtStockName, "3, 2, fill, default");
		txtStockName.setColumns(10);

		JLabel lblNumberOfUnits = new JLabel("Number of Units");
		panelPlaceOrder.add(lblNumberOfUnits, "1, 4, left, center");

		txtNumberUnits = new JTextField();
		txtNumberUnits.setColumns(10);
		panelPlaceOrder.add(txtNumberUnits, "3, 4, fill, default");

		panelPlaceOrder.add(btnPlaceOrder, "3, 8");

	}

	public ArrayList<StockResume> getStockResume() {
		return stockResume;
	}

	@Override
	/**
	 *@param clientComm
	 *Receives the client and displays the orders
	 */
	public void start(ClientComm clientComm) {
		this.client = (ClientCommunication) clientComm;
		setStockResume(this.orderResume.getSellOrders(), this.stockResume);
		setStockResume(this.orderResume.getBuyOrders(), this.stockResume);
		for (StockResume sr : this.stockResume) {
			if (sr.isBuyOrder()) {
				listModelBuy.addElement(sr);
			} else {

				listModelSell.addElement(sr);

			}

		}

	}

	public OrderResume getOrderResume() {
		return orderResume;
	}

	public void setOrderResume(OrderResume orderResume) {
		this.orderResume = orderResume;
	}

	public ClientComm getClient() {
		return client;
	}

	public void setClient(ClientCommunication client) {
		this.client = client;
	}

	public JList<StockResume> getListPaneSell() {
		return listPaneSell;
	}

	public void setListPaneSell(JList<StockResume> listPaneSell) {
		this.listPaneSell = listPaneSell;
	}

	public JList<StockResume> getListPaneBuy() {
		return listPaneBuy;
	}

	public void setListPaneBuy(JList<StockResume> listPaneBuy) {
		this.listPaneBuy = listPaneBuy;
	}
}







